
	/***********************************************************************************************

		@API
		Module: Locale

		Methods:
			mod		use					(id*)
			mod		set					(id, data)
			data	get					(id*)
			id		current			()
			a			list				()
			b			isDefined		(id)

		Events:
			beforeChange, change

		Note:
			supported locale ids ex: en-us, de, it_IT ..

			locale update:  all the sub-object are replaced. The only exception is
											d_formats because has well know properties. tzs -> nonsense and so

		Data legend:
													required		default
													----------------------------------------------------
			+Date
			name									y
			language
			region

			d_days								y
			d_days_short					-						first three letters of days
			d_days_ordinals				-						""
			d_months							y
			d_months_short				-						first three letters of months
			d_am									-						"AM"
			d_pm									-						"PM"
			d_formats							y						-
			d_first_wday					-						0
			d_tzs									y						-

			+Number
			n_sep_dec							-						"."
			n_sep_zero						-						","
			n_format							-						null

	************************************************************************************************/

	//Module init
	//-------------------------------------------------------------------------------
	jsl.Locale = (function() {
		try {
			var mod

			mod					= new jsl.Module("jsl.Locale")
			mod.__c			= null
			mod.__ls		= {}

			mod.events("beforeChange", "change")
			mod.eventAction("change", function(e) { jsl.console.info("sys.LocaleChange", e.from + " -> " + e.to) })

			return mod
		}
		catch(e) {
			jsl.throwError(e, "jsl.Locale")
		}
	})()

	//-------------------------------------------------------------------------------
	jsl.Locale.use = function(id) {
		try {
			var nl, e

			//!
			if(arguments.length > 1)	throw jsl.ParamError()
			if(arguments.length)			jsl.validate(id, "s+", "id")//!

			nl = id ? this.__normalize(id) : this.__ni_loc_get()

			//!
			if(arguments.length && !this.__ls[nl])	throw jsl.ParamError("NotDefined:id")//!

			if(nl !== this.__c) {

				e = new jsl.Event({ from: this.__c, to: nl })

				this.throwEvent("beforeChange", e)
				this.__c = nl
				this.throwEvent("change", e)
			}

			return this
		}
		catch(e) {
			jsl.throwError(e, this, arguments)
		}
	}
	//-------------------------------------------------------------------------------
	jsl.Locale.set = function(id, data) {
		try {
			var ts, o, pid, l, dn, d, from, a, len, name
			var clone, augment, fs

			//!
			if(arguments.length !== 2)	throw jsl.ParamError()
			jsl.validate(id, "sr/\\w+(\\-\\w+)?(:\\w+(\\-\\w+)?)?(\\.[\\w]+)?", "id")//!

			ts		= id.split(":")
			from	= ts.length > 1 ? this.__normalize(ts[0]) : ""
			l			= this.__normalize((ts.length > 1 ? ts[1] : ts[0]).split(".")[0])
			pid		= id.split(".")[1]
			o 		= !pid
			dn		= o ? "data." : ""

			clone		= jsl.Object.clone
			augment	= jsl.Object.augment
			name		= o ? data.name : (pid === "name" ? data : null)

			//!
			if(from && !this.__ls[from])	throw jsl.ParamError("NotDefined:id(from)")
			if(from === l)								throw jsl.ParamError("BadValue:id")
			if(from && this.__ls[l])			throw jsl.ParamError("OperationDenied:inherit")

			if(o)													jsl.validate(data, "o", "data")
			else if(!this.__ls[l])				throw jsl.ParamError("NotDefined:id(" + l + ")")
			//!

			if(o) {
				if(from)
					d = clone(this.__ls[from], 1)

				if(this.__ls[l])
					if(d)	{
						fs 					= augment(d.d_formats, this.__ls[l].d_formats)
						d 					= augment(d, this.__ls[l])
						d.d_formats = fs
					}
					else
						d = clone(this.__ls[l], 1)

				if(d) {
					fs 					= augment(d.d_formats, data.d_formats ? data.d_formats : {})
					d 					= augment(d, data)
					d.d_formats = fs
				}
				else
					d = clone(data, 1)
			}
			else
				if(pid === "d_formats")	(d = {})[pid] = augment(this.__ls[l][pid], data)
				else										(d = {})[pid] = clone(data, 1)

			//!
			if(o || pid === "d_days")					jsl.validate(d.d_days		, "al", dn + "d_days")
			if(o || pid === "d_months")				jsl.validate(d.d_months	, "al", dn + "d_months")
			if(!this.__ls[l] && name == null)	throw jsl.ParamError("Required:" 				+ dn + "name")
			if( this.__ls[l] && name != null)	throw jsl.ParamError("OperationDenied:" + dn + "name")//!

			//default values
			//-------------------------------------------------------------------------------
			if(o && !this.__ls[l]) {

				if(!d.d_days_short)	{

					d.d_days_short = []
					for(a = 0, len = d.d_days.length; a < len; a++)
						d.d_days_short[a] = d.d_days[a].slice(0, 3)
				}

				if(!d.d_months_short)	{

					d.d_months_short = []
					for(a = 0, len = d.d_months.length; a < len; a++)
						d.d_months_short[a] = d.d_months[a].slice(0, 3)
				}

				if(!d.d_formats)
					d.d_formats = { date: "yyyy/mmy/dd", date_long: "Month d, yyyy", month_day: "Month dd", month_year: "Month, yyyy" }

				if(!d.d_days_ordinals)		d.d_days_ordinals = ["??"]
				if(!d.d_first_wday)				d.d_first_wday = 0
				if(!d.d_am)								d.d_am = "AM"
				if(!d.d_pm)								d.d_pm = "PM"

				if(!d.n_sep_dec)					d.n_sep_dec 	= "."
				if(!d.n_sep_zero)					d.n_sep_zero 	= ","
			}

			//!
			//date
			//-------------------------------------------------------------------------------
			if(name != null)											jsl.validate(d.name								, "sr/^[^\\(]+\\([^\\)]+\\)\\s*$", dn + "name")
			if(o || pid === "d_days_short")				jsl.validate(d.d_days_short 			, "al"		, dn + "d_days_short")
			if(o || pid === "d_months_short")			jsl.validate(d.d_months_short			, "al"		, dn + "d_months_short")
			if(o || pid === "d_formats")					jsl.validate(d.d_formats					, "o"			, dn + "d_formats")
			if(o || pid === "d_days_ordinals")		jsl.validate(d.d_days_ordinals		, "al"		, dn + "d_days_ordinals")
			if(o || pid === "d_first_wday")				jsl.validate(d.d_first_wday				, "i[0,6]", dn + "d_first_wday")
			if(o || pid === "d_am")								jsl.validate(d.d_am								, "s"			, dn + "d_am")
			if(o || pid === "d_pm")								jsl.validate(d.d_pm		 						, "s"			, dn + "d_pm")
			if(o || pid === "d_tzs")							jsl.validate(d.d_tzs							, "o"			, dn + "d_tzs")

			//sub-contents
			if(o || pid === "d_days")
			for(a = 0, len = d.d_days.length; a < len; a++)	jsl.validate(d.d_days[a], "s+", dn + "d_days[" + a + "]")

			if(o || pid === "d_days_short")
			for(a = 0, len = d.d_days_short.length;	a < len; a++)	jsl.validate(d.d_days_short[a], "s+", dn + "d_days_short[" + a + "]")

			if(o || pid === "d_months")
			for(a = 0, len = d.d_months.length; a < len; a++)	jsl.validate(d.d_months[a], "s+", dn + "d_months[" + a + "]")

			if(o || pid === "d_months_short")
			for(a = 0, len = d.d_months_short.length;	a < len; a++)	jsl.validate(d.d_months_short[a], "s+", dn + "d_months_short[" + a + "]")

			if(o || pid === "d_formats") {
        jsl.validate(d.d_formats.date				, "t[f,s+]", dn + "d_formats.date")
        jsl.validate(d.d_formats.date_l			, "t[f,s+]", dn + "d_formats.date_l")
        jsl.validate(d.d_formats.time				, "t[f,s+]", dn + "d_formats.time")
        jsl.validate(d.d_formats.time_l			, "t[f,s+]", dn + "d_formats.time_l")
        jsl.validate(d.d_formats.month_day	, "t[f,s+]", dn + "d_formats.month_day")
        jsl.validate(d.d_formats.month_year	, "t[f,s+]", dn + "d_formats.month_year")
			}

			if(o || pid === "d_days_ordinals")
			for(a = 0, len = d.d_days_ordinals.length ; a < len; a++)
				if(d.d_days_ordinals[a] != null)
					jsl.validate(d.d_days_ordinals[a], "s+", dn + "d_days_ordinals[" + a + "]")

			if(o || pid === "d_tzs")
				for(a in d.d_tzs)
					if(d.d_tzs.hasOwnProperty(a)) {
						jsl.validate(a					, "sr/^\\-?\\d{1,3}$"	, dn + "d_tzs[" + a + "]")
						jsl.validate(d.d_tzs[a]	, "sr/^\\w+(:\\w+)?$"	, dn + "d_tzs["	+ d.d_tzs[a] + "]")
					}

			//numbers
			//-------------------------------------------------------------------------------
			if(o || pid === "n_sep_dec")	jsl.validate(d.n_sep_dec	, "s+", dn + "n_sep_dec")
			if(o || pid === "n_sep_zero")	jsl.validate(d.n_sep_zero	, "s+", dn + "n_sep_zero")

			if(d.n_format)
			if(o || pid === "n_format")		jsl.validate(d.n_format	, "f"	, dn + "n_format")
			//!

			if(name) {
				d.language 	= name.match(/\s*([^\(]+?)\s*\(/)[1]
				d.region		= name.match(/\(\s*([^\)]+?)\s*\)/)[1]
			}

			if(o)	{
				this.__ls[l] 		= d
				this.__ls[l].id = l
			}
			else
				this.__ls[l][pid]	= d[pid]

			return this
		}
		catch(e) {
			jsl.throwError(e, this, arguments)
		}
	}
	//-------------------------------------------------------------------------------
	jsl.Locale.get = function(id) {
		try {
			var lid

			//!
			if(arguments.length > 1)								throw jsl.ParamError()
			if(arguments.length)										jsl.validate(id, "s+", "id")//!

			if(id) lid = this.__normalize(id)
			//!
			if(arguments.length && !this.__ls[lid])	throw jsl.ParamError("NotDefined:id")//!


			if(!id && !this.__c)
				this.current()

			return jsl.Object.clone(this.__ls[id ? lid : this.__c], 1)
		}
		catch(e) {
			jsl.throwError(e, this, arguments)
		}
	}
	//-------------------------------------------------------------------------------
	jsl.Locale.current = function() {
		try {
			//!
			if(arguments.length)	throw jsl.ParamError()//!

			if(!this.__c) {
				this.__c = this.__ni_loc_get()//!
				if(!this.__ls[this.__c])	throw jsl.ParamError("sys.LocaleNotDefined:" + this.__c)//!
			}

			return this.__c
		}
		catch(e) {
			jsl.throwError(e, this, arguments)
		}
	}
	//-------------------------------------------------------------------------------
	jsl.Locale.list = function() {
		try {
			var l = []

			//!
			if(arguments.length)	throw jsl.ParamError()//!

			for(var id in this.__ls)
				if(this.__ls.hasOwnProperty(id))
					l.push(id)

			//can be not in alphabetic order
			return l.sort()
		}
		catch(e) {
			jsl.throwError(e, this, arguments)
		}
	}
	//-------------------------------------------------------------------------------
	jsl.Locale.isDefined = function(id) {
		try {
			//!
			if(arguments.length !== 1)	throw jsl.ParamError()
			jsl.validate(id, "s+", "id")
			//!

			return !!this.__ls[this.__normalize(id)]
		}
		catch(e) {
			jsl.throwError(e, this, arguments)
		}
	}
	//-------------------------------------------------------------------------------
	jsl.Locale.__normalize = function(id) {
		try {
			var nid

			if(id.indexOf("-") !== -1) nid = id + ""
			//some locales have awkward ids ex: kk_Cyrl
			else if(id.indexOf("_") !== -1) nid = id.replace(/(_)[^_]+$/, "&1")
			else														nid = id + "-" + id
			return nid.toLowerCase()
		}
		catch(e) {
			jsl.throwError(e, this, arguments)
		}
	}
